﻿using System.ComponentModel;
using System.Windows;

using Microsoft.Practices.Composite.Events;
using Microsoft.Practices.Composite.Modularity;
using Microsoft.Practices.Composite.Presentation.Events;
using Microsoft.Practices.Composite.Regions;
using Microsoft.Practices.Unity;

using Matchingo.Common.Constants;
using Matchingo.Common.Types.Enumerations;
using Matchingo.Common.Types.Events;
using Matchingo.Common.Types.Interfaces;

namespace Matchingo.Modules.TitleScreenModule
{
    public class TitleScreenViewModel : DependencyObject, IMenuItem, IModule, INotifyPropertyChanged
    {
        #region ========== Private Properties ==========

        private ITitleScreenView View;

        private readonly IUnityContainer Container;
        private readonly IRegionManager RegionManager;
        private readonly IMenuFlowProvider FlowProvider;
        private readonly IGameExecutionFacade GameExecutionFacade;
        private readonly IGameSettingsProvider SettingsProvider;
        private readonly IEventAggregator EventAggregator;

        #endregion

        #region =========== Public Properties ===========

        public string PlayerName
        {
            get { return SettingsProvider.GameSettings.PlayerName; }
            private set
            {                
                SettingsProvider.GameSettings.PlayerName = value;
                SettingsProvider.SaveSettings(); // TODO:: we should not be interacting with this GameSettings object directly?
                NotifyPropertyChanged("PlayerName");
            }
        }

        #endregion

        #region ========== Constructor ==========

        public TitleScreenViewModel(IUnityContainer container, IEventAggregator eventAggregator, IRegionManager regionManager, 
            IMenuFlowProvider flowProvider, IGameExecutionFacade gameFacade, IGameSettingsProvider settingsProvider)
        {
            Container = container;
            SettingsProvider = settingsProvider;
            RegionManager = regionManager;
            FlowProvider = flowProvider;
            GameExecutionFacade = gameFacade;
            EventAggregator = eventAggregator;
        }

        #endregion

        #region ========== Public Methods ==========

        public void Initialize()
        {
            View = Container.Resolve<ITitleScreenView>();
            View.Initialize(this);

            // register this UserControl with our UI Flow Provider
			FlowProvider.RegisterUIModule(this, MenuModuleNames.ModuleNames.TitleScreenMenu, View.RootElement);

            IRegion region = RegionManager.Regions[CommonConstants.SHELL_REGION_TitleScreen];
            region.Add(View);

            SettingsProvider.PropertyChanged += (s, e) => NotifyPropertyChanged("PlayerName");

            EventAggregator.GetEvent<MenuSelectionChangedEvent>().Subscribe(SelectedMenuChanged, ThreadOption.UIThread);            
        }

        public void ToggleMenu()
        {
            // if we are on any screen other than the title page then we go to the title page, otherwise we close the menu
            if (FlowProvider.CurrentMenuItem == MenuModuleNames.ModuleNames.TitleScreenMenu)
            {
                GameExecutionFacade.CloseMenu();
            }
            else
            {
                GameExecutionFacade.ShowMenu(MenuModuleNames.ModuleNames.TitleScreenMenu);
            }
        }

        public void StartNewGame(string playerName)
        {
            PlayerName = playerName;
            GameExecutionFacade.StartNewGame(false, true);
        }

        public void ToggleTitlePage()
        {
            if (FlowProvider.CurrentMenuItem == MenuModuleNames.ModuleNames.None)
                GameExecutionFacade.ShowMenu(MenuModuleNames.ModuleNames.TitleScreenMenu);
            else
                GameExecutionFacade.CloseMenu();                
        }

        public void ShowAboutScreen() // TODO:: update other methods with same naming convention
        {
            GameExecutionFacade.ShowMenu(MenuModuleNames.ModuleNames.AboutMenu);
        }

        // TODO:: can we get rid of these methods and have the view call with the enum, or is that bad practice?
        public void ShowOptions()
        {
            GameExecutionFacade.ShowMenu(MenuModuleNames.ModuleNames.OptionsMenu);
        }

        public void ShowHighScores()
        {
            GameExecutionFacade.ShowMenu(MenuModuleNames.ModuleNames.HighScoreMenu);
        }

        public bool TransitionMenu(InOutEnumeration.InOut inOrOut, DirectionNames.Direction direction, bool skipAnimation)
        {
            if (inOrOut == InOutEnumeration.InOut.In)
            {
                View.ShowScreen(direction, skipAnimation);
            }
            else
            {
                View.HideScreen(direction, skipAnimation);
            }

            return true;
        }

        #endregion
        
        #region ========== Private Methods ==========

        private void NotifyPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged == null)
                return;

            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion

        #region ========== Event Handlers ==========

        // NOTE:: event handlers fired by the EventAggregator must be public in Silveright
        public void SelectedMenuChanged(MenuModuleNames.ModuleNames menu)
        {
            switch (menu)
            {
                case MenuModuleNames.ModuleNames.None:
                    View.ChangeTitleArrowDirection(DirectionNames.Direction.Down);
                    break;
                case MenuModuleNames.ModuleNames.AboutMenu:
                    View.ChangeTitleArrowDirection(DirectionNames.Direction.Up);
                    break;
                case MenuModuleNames.ModuleNames.HighScoreMenu:
                    View.ChangeTitleArrowDirection(DirectionNames.Direction.Left);
                    break;
                case MenuModuleNames.ModuleNames.OptionsMenu:
                    View.ChangeTitleArrowDirection(DirectionNames.Direction.Right);
                    break;
                case MenuModuleNames.ModuleNames.TitleScreenMenu:
                    View.ChangeTitleArrowDirection(DirectionNames.Direction.Up);
                    break;
            }            
        }

        #endregion

        #region =========== Public Events ==========

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

    }
}
